package com.sd365.gateway.core.filter;
import com.sd365.gateway.core.constant.BusinessResultConsts;
import com.sd365.gateway.core.handler.IGatewayEntryHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.List;

/**
 * @class GatewayEntryFilter
 * @classdesc 重构了原来的网关的类，判断Token是否存在，转发到授权中心
 * @author abel.zhan
 * @version 1.0.0
 * @date 2020/12/18
 */
@Slf4j
@Component
public class GatewayEntryFilter implements GlobalFilter, Ordered {
    /**
     * 调用handler处理业务逻辑
     */
    @Autowired
    private IGatewayEntryHandler gatewayEntryHandler;
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
            String URI = exchange.getRequest().getURI().toString();
            log.debug("请求的url：{} this{}", URI, this);
            /**
             * 是否包含在资源的白名单列表以及通用资源访问表如果包含则放行，其中包含访问认证接口为了安全需要做限流避免
             * 从一个ip发起大量的请求
             * */
            if (gatewayEntryHandler.detectConfigWhiteList(URI) || gatewayEntryHandler.detectCommonResource(URI)) {
                return chain.filter(exchange);
            } else {
                List<String> accessToken = exchange.getRequest().getHeaders().get("accessToken");
                // 如果包含token 且 token签名验证通过这进行鉴权
                if (!CollectionUtils.isEmpty(accessToken)) {

                    try {
                        // 如果签名验证没有通过则请求访问被终止
                        if (!gatewayEntryHandler.verifySign(accessToken.get(0))){
                            exchange.getResponse().setStatusCode(HttpStatus.NON_AUTHORITATIVE_INFORMATION );
                            return exchange.getResponse().setComplete();
                        }

                        Integer authorResult=gatewayEntryHandler.dispatch2Authorize(accessToken.get(0),URI);
                        if (BusinessResultConsts.AUTHOR_RESULT_TRUE ==authorResult) {
                            log.debug("请求的url：{} this{},{}", URI, this,"带token去鉴权成功");
                            return chain.filter(exchange);
                        } else {
                            log.debug("请求的url：{} this{},{}", URI, this,"带token去鉴权失败");
                            // 如果是 希望将明确的应答返回到前端  token过期，token重新续约，认证没通过
                            exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
                            return exchange.getResponse().setComplete();
                        }
                    }catch (Exception ex){
                        log.info("请求带toke转发去鉴权发生异常:{}", ex);
                        exchange.getResponse().setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
                        return exchange.getResponse().setComplete();
                    }
                } else { // 否则没有token也不属于白名单的资源
                        log.debug("请求的url：{} this{},{}", URI, this,"无token去查询公共资源失败");
                        exchange.getResponse().setStatusCode(HttpStatus.NOT_ACCEPTABLE);
                        return exchange.getResponse().setComplete();
                }
            }
    }

    /**
     *  前一个过滤为为 黑名单过滤器 如果没有通过黑名单过滤器不进入该过滤器
     * @return
     */
    @Override
    public int getOrder() {
        return 2;
    }

}
